<?php

namespace Yolo\Components\RpcClient;

use Yolo\Components\ApplicationRegistry\ApplicationRegistry;
use Yolo\Di\Annotations\Initializer;
use Yolo\Di\Annotations\Singleton;
use Yolo\Errors\ConfigInvalidException;
use Yolo\Service\ApplicationContainer;

#[Singleton]
class ClientManager
{
    /**
     * @var ClientInterface[] $clients Clients
     */
    protected array $clients = [];

    public function __construct(
        private readonly ApplicationContainer $container,
        private readonly ApplicationRegistry $applicationRegistry,
    ) {}

    #[Initializer]
    public function init(): void
    {
        if (!$this->applicationRegistry->enabled()) {
            return;
        }

        $this->addClient($this->getClient('ApplicationRegistry'));
    }

    /**
     * add a client
     * @param ClientInterface $client
     * @return void
     */
    public function addClient(ClientInterface $client): void
    {
        $this->clients[$client->getServiceName()] = $client;
    }

    /**
     * Get a client
     * @param string $serviceName
     * @return ClientInterface
     * @throws ConfigInvalidException
     */
    public function getClient(string $serviceName): ClientInterface
    {
        if (isset($this->clients[$serviceName])) {
            return $this->clients[$serviceName];
        }

        $client = $this->initClient($serviceName);
        $this->addClient($client);
        return $client;
    }

    /**
     * Init a client
     * @param string $serviceName
     * @return ClientInterface
     * @throws ConfigInvalidException
     */
    private function initClient(string $serviceName): ClientInterface
    {
        $url = $this->container->getConfig()->getClientConnection($serviceName);
        if ($url) {
            return new Client(
                $serviceName,
                $url,
            );
        }

        if (!$this->applicationRegistry->enabled()) {
            throw new ConfigInvalidException("Config rpc.client.connections.$serviceName not found");
        }

        $service = $this->applicationRegistry->discovery($serviceName);

        return new Client(
            $serviceName,
            $service['rpc']['server']['instance'],
        );
    }
}
